package com.yexiao.cofe.util;

import org.springframework.stereotype.Component;

/**
 * 分布式Id 工具类
 * 基于 Snowflake 算法，生成的ID是一个 64 位的长整型数字，其结构如下
 * 1 位符号位（始终为 0）
 * 41 位时间戳（精确到毫秒级）
 * 5 位数据中心 ID
 * 5 位机器 ID
 * 12 位序列号
 *
 * @author lkl
 * @since 2025/4/2
 */
@SuppressWarnings("all")
@Component
public class SnowflakeIdGenerator {
    private final long startTimeStamp = 1609459200000L; // 2021-01-01 00:00:00
    private final long dataCenterIdBits = 5L;
    private final long machineIdBits = 5L;
    private final long sequenceBits = 12L;

    private final long machineIdShift = sequenceBits;
    private final long dataCenterIdShift = sequenceBits + machineIdBits;
    private final long timestampLeftShift = sequenceBits + machineIdBits + dataCenterIdBits;

    private final long sequenceMask = -1L ^ (-1L << sequenceBits);
    private long sequence = 0L;
    private long lastTimestamp = -1L;

    private Long dataCenterCode;
    private Long machineCode;

    // 默认数据中心id和机器id，随便写的，没讲究
    private final Long Default_Data_Center_Code = 46512L;
    private final Long Default_Machine_Code = 65478L;

    /* ==== 构造方法 ==== */
    public SnowflakeIdGenerator() {
        setValue(Default_Data_Center_Code, Default_Machine_Code);
    }

    public SnowflakeIdGenerator(long dataCenterId, long machineId) {
        checkParam(dataCenterId, machineId);
        setValue(dataCenterId, machineId);
    }

    /**
     * 生成分布式id
     */
    public synchronized long nextId() {
        long currentTimestamp = System.currentTimeMillis();
        if (currentTimestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate id for " + (lastTimestamp - currentTimestamp) + " milliseconds");
        }
        if (currentTimestamp == lastTimestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                currentTimestamp = waitNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0L;
        }
        lastTimestamp = currentTimestamp;
        return ((currentTimestamp - startTimeStamp) << timestampLeftShift) |
                (this.dataCenterCode << dataCenterIdShift) |
                (this.machineCode << machineIdShift) |
                sequence;
    }

    /**
     * 生成分布式id
     * @param dataCenterId 数据中心id
     * @param machineId 机器id
     */
    public synchronized long nextId(long dataCenterId, long machineId) {
        checkParam(dataCenterId, machineId);
        setValue(dataCenterId, machineId);
        long id = nextId();
        reInitValue();
        return id;
    }

    private void checkParam(long dataCenterId, long machineId) {
        long maxDataCenterId = -1L ^ (-1L << dataCenterIdBits);
        long maxMachineId = -1L ^ (-1L << machineIdBits);
        if (dataCenterId > maxDataCenterId || dataCenterId < 0) {
            throw new IllegalArgumentException("数据中心ID不能大于 " + maxDataCenterId + " 或小于 0");
        }
        if (machineId > maxMachineId || machineId < 0) {
            throw new IllegalArgumentException("机器ID不能大于 " + maxMachineId + " 或小于 0");
        }
    }

    private long waitNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }

    private void setValue(long dataCenterId, long machineId) {
        this.dataCenterCode = dataCenterId;
        this.machineCode = machineId;
    }

    private void reInitValue() {
        setValue(Default_Data_Center_Code, Default_Machine_Code);
    }
}
